﻿using System;

public class Elevator
{
    private static int elevatorCounter = 0;
    private int index;

    public Signal2<Integer, Integer> currentFloorChanged = new Signal2<Integer, Integer>();

    private ArrayList<Boolean> floorList;
    private Set<Integer> queue;

    private Date timer;
    private Date doorTimer;
    private int people;
    private int capacity;
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private int nextFloor;
    private boolean moving; // is the elevator moving
    private boolean goingUp;
    private boolean doorClosed;
    private boolean doorClosedAttempt;
    private boolean changedDirection;
    private boolean changeDirection;
    private double speed;
    private double acceleration;

    /*
     * Elevator constructor
     */
    public Elevator(int minF, int maxF, ArrayList<Boolean> fl)
    {
        this.minFloor = minF;
        this.maxFloor = maxF;
        this.floorList = fl;
        this.currentFloor = 0;
        this.nextFloor = 0;

        this.index = elevatorCounter++;

        this.goingUp = true;
        this.queue = new HashSet<Integer>();

        this.doorClosed = true;
        this.doorClosedAttempt = false;
        // this.triggerChangeDirection = false;
        this.changeDirection = false;
        this.moving = false;
    }

    /*
     * Logic to calculate where the elevator should go next
     */
    public void elevatorAction()
    {
        if (!this.isMoving())
        {
            if (!changeDirection)
            {
                if (this.goingUp() && (queue.isEmpty() || this.currentFloor >= this.maxFloor))
                {
                    changeDirection = true;
                    this.goingUp = false;
                    //Console.WriteLine("changing direction");
                }
                else if (!this.goingUp() && (queue.isEmpty() || this.currentFloor <= this.minFloor))
                {
                    changeDirection = true;
                    this.goingUp = true;
                }
                else if (this.goingUp())
                {
                    int upMin = this.getQueueMin();

                    if (upMin >= this.minFloor && upMin <= this.maxFloor && upMin >= this.currentFloor)
                    {
                        this.nextFloor = upMin;
                        this.moving = true;
                    }
                    else
                    {
                        //Console.WriteLine("ee:" + upMin);
                        //Console.WriteLine("up: neither were appropriate");
                    }
                }
                else if (!this.goingUp())
                {
                    int downMax = this.getQueueMax();

                    if (downMax <= this.maxFloor && downMax >= this.minFloor && downMax <= this.currentFloor)
                    {
                        this.nextFloor = downMax;
                        this.moving = true;
                    }
                    else
                    {
                        //Console.WriteLine("down: neither were appropriate");
                    }
                }
            }
            else if (changeDirection)
            {
                changeDirection = false;
            }

        }

        this.timer = new Date();
    }

    /*
     * Logic to move the elevator to the nextFloor
     */
    public void moveElevator() {
        if (this.isMoving()) {

            if (this.currentFloor == this.nextFloor) {
                this.queue.remove(this.nextFloor);
                this.doorClosed = false;
                this.moving = false;
            } else {
                if ((new Date().getTime() - this.timer.getTime()) > 3000) {
                    if (this.currentFloor < this.nextFloor) { //elevator is moving up
                        //this.currentFloor++;
                        this.changeCurrentFloor(true);
                        this.timer = new Date();
                        Console.WriteLine("Current Floor: " + this.currentFloor);
                    } else if (this.currentFloor > this.nextFloor) {
                        //this.currentFloor--;
                        this.changeCurrentFloor(false);
                        this.timer = new Date();
                        Console.WriteLine("Current Floor: " + this.currentFloor);
                    }
                }
            }

        }
    }



     private void addToQueue(int floor)
    {
        this.queue.add(floor);
    }

    /*
     * Goes to the users destination
     */
    /*  void stopAtFloor(Boolean goUp, int floorDst) {
          stopQueue.add(floorDst);
      }*/

    /*
     * Returns whether the elevator stops at this floor
     */
    boolean goesToFloor(int floorID)
    {
        return floorList.get(floorID).booleanValue();
    }

    /*
     * Returns whether the lift is moving
     */
    boolean isMoving()
    {
        return this.moving;
    }

    /*
     * Returns whether the door is closed
     */
    boolean isDoorClosed()
    {
        return this.doorClosed;
    }

    /*
     * Set the closing/opening of door
     */
    void setDoorClosed(boolean d) {
        if (!doorClosedAttempt) {
            doorTimer = new Date();
            doorClosedAttempt = true;
        } else if (doorClosedAttempt && (new Date().getTime() - doorTimer.getTime()) > 1000) {
            this.doorClosed = d;
            Console.WriteLine("Door closed: " + d);
            this.doorClosedAttempt = false;
        }
    }

    /*
     * Returns the floor the elevator is on
     */
    int getCurrentFloor()
    {
        return this.currentFloor;
    }

    /*
     * Returns if the elevator is going up or down
     */
    boolean goingUp()
    {
        return this.goingUp;
    }

    /*
     * Adds a person to the counter
     */
    void addPerson()
    {
        /*     if (goUp){
        this.queueUp.add(floorDst);
        } else {
        this.queueDown.add(floorDst);
        }*/
        this.people++;
    }

    /*
     * Remove a person from the counter
     */
    void removePerson()
    {
        this.people--;
    }

    /*
     * Gets the number of people on the elevator
     */
    int getPeople()
    {
        return this.people;
    }
    /*
     * Returns true if the elevator is not being used
     */
    boolean isElevatorFree()
    {
        if (this.isMoving() && this.queue.isEmpty())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    void changeCurrentFloor(boolean increase)
    {
        if (increase)
        {
            this.currentFloor++;
        }
        else
        {
            this.currentFloor--;
        }
        this.currentFloorChanged.emit(this.index, this.currentFloor);
    }


    int getQueueMax()
    {
        int maximumFloor = Integer.MIN_VALUE;
        Iterator it = queue.iterator();
        while (it.hasNext())
        {
            int thisFloor = (Integer)it.next();
            if (thisFloor > maximumFloor)
            {
                maximumFloor = thisFloor;
            }
        }
        return maximumFloor;
    }

    int getQueueMin()
    {
        int minimumFloor = Integer.MAX_VALUE;
        Iterator it = queue.iterator();
        while (it.hasNext())
        {
            int thisFloor = (Integer)it.next();
            if (thisFloor < minimumFloor)
            {
                minimumFloor = thisFloor;
            }
        }
        return minimumFloor;
    }

}